package kits

import (
	"encoding/json"
	"errors"
	"strconv"
	"strings"
)

type jsonType int8

const (
	JSONNumber  jsonType = iota // JSON 数值类型，整形、浮点型
	JSONString                  // JSON 字符串类型
	JSONBoolean                 // JSON 布尔类型
	JSONArray                   // JSON 数组类型
	JSONObject                  // JSON 对象类型
	JSONNull                    // JSON 空对象
)

// JsonNode JSON 结构
type JsonNode struct {
	r *string              // JSON 原始字符串，解析的时候存储
	o map[string]*JsonNode // JSON 对象类型
	a []*JsonNode          // JSON 数组类型
	v interface{}          // JSON 字段值
	t jsonType             // JSON 字段值类型
}

// JSON JSON 对象
var JSON JsonNode

// Parse 从字符串解析为JSON对象
func (jn *JsonNode) Parse(val string) (*JsonNode, error) {
	val = strings.TrimSpace(val)
	jn.r = &val
	if strings.HasPrefix(val, "{") && strings.HasSuffix(val, "}") {
		var jval map[string]interface{}
		if err := json.Unmarshal([]byte(val), &jval); err != nil {
			return nil, err
		}
		if rst, err := jn.parseMap(jval); err != nil {
			return nil, err
		} else {
			jn.o = rst.o
			return jn, nil
		}

	} else if strings.HasPrefix(val, "[") && strings.HasSuffix(val, "]") {
		var jval []interface{}
		err := json.Unmarshal([]byte(val), &jval)
		if err != nil {
			return nil, err
		}
		return jn.parseSlice(jval)
	} else {
		return nil, errors.New("invalid JSON string")
	}
}

// ToString 转换为JSON格式字符串
func (jn *JsonNode) ToString(v interface{}) string {
	jsonVal, err := json.Marshal(v)
	if err != nil {
		return "{}"
	}
	return string(jsonVal)
}

// IsEmpty 是否空JSON
func (jn *JsonNode) IsEmpty() bool {
	return jn.Size() == 0
}

// IsArray 是否JSONArray类型
func (jn *JsonNode) IsArray() bool {
	return jn.o == nil && jn.a != nil
}

// IsObject 是否JSONObject 类型
func (jn *JsonNode) IsObject() bool {
	return jn.o != nil && jn.a == nil
}

// Size 长度，对象类型：字段个数，数组类型：数组长度
func (jn *JsonNode) Size() int {
	if jn.IsArray() {
		return len(jn.a)
	} else if jn.IsObject() {
		return len(jn.o)
	}
	return 0
}

// Keys 获取JSON对象所有字段名称
func (jn *JsonNode) Keys() []string {
	if jn.IsObject() && !jn.IsEmpty() {
		i := 0
		keys := make([]string, len(jn.o))
		for k := range jn.o {
			keys[i] = k
			i++
		}
		return keys
	}
	return []string{}
}

// Name 获取JSON对象指定字段的值
func (jn *JsonNode) Name(key string) *JsonNode {
	if jn.IsObject() && !jn.IsEmpty() {
		return jn.o[key]
	}
	return nil
}

// Index 获取JSON数组指定索引的值
func (jn *JsonNode) Index(index int) *JsonNode {
	if jn.IsArray() && !jn.IsEmpty() && index < jn.Size() {
		return jn.a[index]
	}
	return nil
}

// String 获取JSON字段指定的值内容，string 类型
func (jn *JsonNode) String() string {
	if jn == nil && jn.r == nil {
		panic(errors.New("invalid string value"))
	}
	return *jn.r
}

// Int64 获取JSON字段指定的值内容，int64类型
func (jn *JsonNode) Int64() int64 {
	if jn == nil && jn.v == nil {
		panic(errors.New("invalid number value"))
	}
	switch jn.t {
	case JSONString:
		if val, err := strconv.ParseFloat(jn.v.(string), 64); err == nil {
			return int64(val)
		} else {
			panic(errors.New("invalid number value"))
		}
	case JSONNumber:
		return int64(jn.v.(float64))
	case JSONBoolean:
		if jn.v.(bool) {
			return 1
		} else {
			return 0
		}
	}
	panic(errors.New("invalid number value"))
}

// Float64 获取JSON字段指定的值内容，float64类型
func (jn *JsonNode) Float64() float64 {
	if jn == nil && jn.v == nil {
		panic(errors.New("invalid number value"))
	}
	switch jn.t {
	case JSONString:
		if val, err := strconv.ParseFloat(jn.v.(string), 64); err == nil {
			return val
		} else {
			panic(errors.New("invalid number value"))
		}
	case JSONNumber:
		return jn.v.(float64)
	case JSONBoolean:
		if jn.v.(bool) {
			return 1
		} else {
			return 0
		}
	}
	panic(errors.New("invalid number value"))

}

// Boolean 获取JSON字段指定的值内容，bool 类型
func (jn *JsonNode) Boolean() bool {
	if jn == nil && jn.v == nil {
		panic(errors.New("invalid boolean value"))
	}
	switch jn.t {
	case JSONString:
		if strings.EqualFold(strings.ToLower(jn.v.(string)), "true") {
			return true
		} else if strings.EqualFold(strings.ToLower(jn.v.(string)), "false") {
			return false
		}
		panic(errors.New("invalid boolean value"))
	case JSONNumber:
		return int64(jn.v.(float64)) > 0
	case JSONBoolean:
		return jn.v.(bool)
	}
	panic(errors.New("invalid boolean value"))
}

// 从map解析为JSON对象
func (jn *JsonNode) parseMap(val map[string]interface{}) (*JsonNode, error) {
	node := &JsonNode{}
	node.o = make(map[string]*JsonNode)
	for k, v := range val {
		if n, err := jn.convert(v); err != nil {
			return nil, err
		} else {
			node.o[k] = n
		}
	}
	return node, nil
}

// 从列表解析为JSON对象
func (jn *JsonNode) parseSlice(val []interface{}) (*JsonNode, error) {
	node := &JsonNode{}
	node.a = make([]*JsonNode, len(val), len(val))
	for i := 0; i < len(val); i++ {
		if n, err := jn.convert(val[i]); err != nil {
			return nil, err
		} else {
			node.a[i] = n
		}

	}
	return node, nil
}

// 转换为JSON Value
func (jn *JsonNode) convert(val interface{}) (*JsonNode, error) {
	//fmt.Printf("Convert -> %v , %T \n", val, val)
	node := &JsonNode{}
	if val == nil {
		node.t = JSONNull
		node.v = nil
		node.r = nil
	} else {
		switch val.(type) {
		case string:
			raw := val.(string)
			node.t = JSONString
			node.v = val
			node.r = &raw
		case float64:
			raw := strconv.FormatFloat(val.(float64), 'f', -1, 64)
			node.t = JSONNumber
			node.v = val
			node.r = &raw
		case bool:
			raw := strconv.FormatBool(val.(bool))
			node.t = JSONBoolean
			node.v = val
			node.r = &raw
		case []interface{}:
			if now, err := jn.parseSlice(val.([]interface{})); err != nil {
				return nil, err
			} else {
				raw := jn.ToString(val)
				node.t = JSONArray
				node.a = now.a
				node.r = &raw
			}
		case map[string]interface{}:
			if now, err := jn.parseMap(val.(map[string]interface{})); err != nil {
				return nil, err
			} else {
				raw := jn.ToString(val)
				node.t = JSONObject
				node.o = now.o
				node.r = &raw
			}
		}
	}
	return node, nil
}
